package com.szcinda.service.dto.organization;

import com.szcinda.repository.*;
import com.szcinda.service.SnowFlakeFactory;
import com.szcinda.service.dto.role.RoleRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class OrganizationServiceImpl implements OrganizationService {

    private final OrganizationRepository organizationRepository;
    private final SnowFlakeFactory snowFlakeFactory;
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;

    public OrganizationServiceImpl(OrganizationRepository organizationRepository, UserRepository userRepository,
                                   RoleRepository roleRepository) {
        this.organizationRepository = organizationRepository;
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
        this.snowFlakeFactory = SnowFlakeFactory.getInstance();
    }

    @Override
    public void create(OrganizationCreateDto createDto) {
        Organization record = organizationRepository.findByNameAndFullName(createDto.getName(), createDto.getFullName());
        Assert.isTrue(record == null, "存在抬头【" + createDto.getName() + "】和全称【" + createDto.getFullName() + "】的组织机构");
        Organization organization = new Organization();
        BeanUtils.copyProperties(createDto, organization);
        organization.setId(snowFlakeFactory.nextId("OG"));
        organizationRepository.save(organization);
    }

    @Override
    public void update(OrganizationUpdateDto updateDto) {
        Organization record = organizationRepository.findById(updateDto.getId());
        record.setName(updateDto.getName());
        record.setFullName(updateDto.getFullName());
        record.setPrefix(updateDto.getPrefix());
        organizationRepository.save(record);
    }

    @Override
    public void delete(String id, String userId) {
        List<Organization> childOrgs = organizationRepository.findByParentIdAndStatus(id, "USING");
        Assert.isTrue(childOrgs.size() == 0, "当前组织机构下存在子组织机构,不能删除");
        List<User> users = userRepository.findByOrganizationId(id);
        Assert.isTrue(users.size() == 0, "当前组织机构下存在系统用户,不能删除");
        organizationRepository.delete(id);
    }

    @Override
    public List<OrganizationTree> findTree() {
        List<Organization> organizations = organizationRepository.findByParentIdIsNullAndStatus("USING");
        List<OrganizationTree> treeList = new ArrayList<>();
        if (organizations.size() > 0) {
            organizations.forEach(organization -> {
                OrganizationTree tree = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
                getChildrenOrg(tree, organization.getId());
                treeList.add(tree);
            });
        }

        return treeList;
    }


    private List<OrganizationTree> findAllTree() {
        List<Organization> organizations = organizationRepository.findByParentIdIsNull();
        List<OrganizationTree> treeList = new ArrayList<>();
        if (organizations.size() > 0) {
            organizations.forEach(organization -> {
                OrganizationTree tree = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
                getAllChildrenOrg(tree, organization.getId());
                treeList.add(tree);
            });
        }

        return treeList;
    }

    @Override
    public List<OrganizationTree> findCurrentTree(String userId) {
        User user = userRepository.findById(userId);
        Role role = roleRepository.findById(user.getRoleId());
        if (role.getName().equals(RoleType.SUPER_ADMIN)) {
            // 返回所有的组织架构
            return findAllTree();
        } else if (RoleType.ADMIN2.equals(role.getName()) || RoleType.ADMIN.equals(role.getName())) {
            // 返回当前机构和子机构
            Organization organization = organizationRepository.findById(user.getOrganizationId());
            OrganizationTree tree = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
            getAllChildrenOrg(tree, organization.getId());
            return Collections.singletonList(tree);
        } else if (role.isEqualAdmin()) {
            // 返回当前机构和子机构
            Organization organization = organizationRepository.findById(user.getOrganizationId());
            OrganizationTree tree = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
            getAllChildrenOrg(tree, organization.getId());
            return Collections.singletonList(tree);
        }
        // 普通用户返回当前机构
        Organization organization = organizationRepository.findById(user.getOrganizationId());
        OrganizationTree tree = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
        return Collections.singletonList(tree);
    }

    @Override
    public List<String> getChildOrgIds(String orgId) {
        List<String> ids = new ArrayList<>();
        ids.add(orgId);
        getChildrenOrg(ids, orgId);
        return ids;
    }

    private void getChildOrgIds(String orgId, List<String> ids) {
        ids.add(orgId);
        getChildrenOrg(ids, orgId);
    }

    @Override
    public List<String> getAllOrgIds() {
        List<Organization> organizations = organizationRepository.findByParentIdIsNull();
        List<String> ids = new ArrayList<>();
        for (Organization organization : organizations) {
            getChildOrgIds(organization.getId(), ids);
        }
        return ids;
    }

    //通过用户ID获取组织机构
    @Override
    public List<String> getOrgIdsByUserId(String userId) {
        List<String> orgIds = new ArrayList<>();
        User user = userRepository.findById(userId);
        Role role = roleRepository.findById(user.getRoleId());
        if (role.getName().equals(RoleType.SUPER_ADMIN)) {
            List<Organization> organizations = this.getAll();
            orgIds.addAll(organizations.stream().map(Organization::getId).collect(Collectors.toList()));
        } else if (RoleType.ADMIN2.equals(role.getName()) || RoleType.ADMIN.equals(role.getName())) {
            orgIds.add(user.getOrganizationId());
            this.getChildrenOrg(orgIds, user.getOrganizationId());
        } else {
            orgIds.add(user.getOrganizationId());
        }
        return orgIds;
    }

    @Override
    public OrganizationTree findCurrentTreeByOrgId(String orgId) {
        Organization organization = organizationRepository.findById(orgId);
        OrganizationTree tree = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
        getChildrenOrg(tree, organization.getId());
        return tree;
    }

    @Override
    public List<Organization> getAllByIds(List<String> ids) {
        return organizationRepository.findByIdIn(ids);
    }

    @Override
    public Organization getById(String id) {
        return organizationRepository.findById(id);
    }

    private void getChildrenOrg(OrganizationTree tree, String parentId) {
        List<Organization> children = organizationRepository.findByParentIdAndStatus(parentId, "USING");
        if (children.size() > 0) {
            List<OrganizationTree> ch = new ArrayList<>();
            children.forEach(organization -> {
                OrganizationTree child = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
                getChildrenOrg(child, organization.getId());
                ch.add(child);
            });
            tree.setChildren(ch);
        }
    }

    private void getAllChildrenOrg(OrganizationTree tree, String parentId) {
        List<Organization> children = organizationRepository.findByParentId(parentId);
        if (children.size() > 0) {
            List<OrganizationTree> ch = new ArrayList<>();
            children.forEach(organization -> {
                OrganizationTree child = new OrganizationTree(organization.getId(), organization.getName(), organization.getPrefix(), organization.getFullName(), organization.getStatus());
                getAllChildrenOrg(child, organization.getId());
                ch.add(child);
            });
            tree.setChildren(ch);
        }
    }

    private void getChildrenOrg(List<String> ids, String parentId) {
        List<Organization> children = organizationRepository.findByParentIdAndStatus(parentId, "USING");
        if (children.size() > 0) {
            children.forEach(organization -> {
                getChildrenOrg(ids, organization.getId());
                ids.add(organization.getId());
            });
        }
    }

    @Override
    public void use(String id) {
        Organization organization = organizationRepository.findById(id);
        organization.setStatus("USING");
        organizationRepository.save(organization);
    }

    @Override
    public void unused(String id) {
        Organization organization = organizationRepository.findById(id);
        organization.setStatus("UNUSED");
        organizationRepository.save(organization);
    }

    @Override
    public List<User> getUsers(String userId) {
        User user = userRepository.findById(userId);
        // 如果是超级管理员，则能查到所有的用户日志，如果是机构管理员，能看到当前机构和子机构的用户日志，普通用户只能看到自己的日志
        Role role = roleRepository.findById(user.getRoleId());
        List<User> users;
        if (role.getName().equals(RoleType.SUPER_ADMIN)) {
            users = userRepository.findAll();
        } else if (RoleType.ADMIN2.equals(role.getName()) || RoleType.ADMIN.equals(role.getName())) {
            List<String> childOrgIds = this.getChildOrgIds(user.getOrganizationId());
            users = userRepository.findByOrganizationIdIn(childOrgIds);
        } else if (role.isEqualAdmin()) {
            List<String> childOrgIds = this.getChildOrgIds(user.getOrganizationId());
            users = userRepository.findByOrganizationIdIn(childOrgIds);
        } else {
            users = Collections.singletonList(user);
        }
        return users;
    }

    @Override
    public List<Organization> getAll() {
        return organizationRepository.findByStatus("USING");
    }
}
